﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using VCommons;
using ConfigCache;
using Commons.Entity;

namespace Commons.Web
{
    public class FileUpload : FileUploadBase, IFileUpload
    {
        /// <summary>
        /// 图片尺寸 数组
        /// </summary>
        public static List<ImageSize> ImageSizeArr = new List<ImageSize>();

        public FileUpload()
        {
            Array.ForEach(ConfigFactory.Instance.GetConfig<FileLoadConfig>().ImageSize, i =>
            {
                ImageSizeArr.Add(new ImageSize(i.Width, i.Height));
            });


        }
        string currPath; //当前路径
        string currFileName;//上传后的文件名

        #region 文件上传WWW服务器及图像服务器

        /// <summary>
        /// 文件流上传
        /// 不生成缩略图集合，使用原始大小，不上传到文件服务器
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="hpf">文件流</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf)
        {
            return this.Image(type, hpf, false, new ImageSize(), false, null);
        }
        /// <summary>
        /// 文件流上传
        /// 不生成缩略图集合，使用原始大小，不上传到文件服务器
        /// </summary>
        /// <param name="type"></param>
        /// <param name="hpf"></param>
        /// <param name="uploadPath">指定上传的目录</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf, string uploadPath)
        {
            return this.Image(type, hpf, false, new ImageSize(), false, uploadPath);
        }
        /// <summary>
        /// 文件流上传
        /// 不生成缩略图集合，使用指定尺寸，不上传到文件服务器
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="hpf">文件流</param>
        /// <param name="imageSize">图像尺寸</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf, ImageSize imageSize)
        {
            return this.Image(type, hpf, true, imageSize, false, null);
        }
        /// <summary>
        /// 文件流上传
        /// 不生成缩略图集合，使用指定尺寸，不上传到文件服务器
        /// </summary>
        /// <param name="type"></param>
        /// <param name="hpf"></param>
        /// <param name="imageSize"></param>
        /// <param name="uploadPath">指定上传的目录</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf, ImageSize imageSize, string uploadPath)
        {
            return this.Image(type, hpf, true, imageSize, false, uploadPath);
        }
        /// <summary>
        /// 文件流上传
        /// 不生成缩略图集合，使用原始大小，可以选择上传到文件服务器
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="hpf">文件流</param>
        /// <param name="IsUploadImageServer">是上传到文件服务器</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf, bool IsUploadImageServer)
        {
            return this.Image(type, hpf, false, new ImageSize(), IsUploadImageServer, null);
        }
        /// <summary>
        /// 文件流上传
        /// 不生成缩略图集合，使用原始大小，可以选择上传到文件服务器
        /// </summary>
        /// <param name="type"></param>
        /// <param name="hpf"></param>
        /// <param name="IsUploadImageServer"></param>
        /// <param name="uploadPath">指定上传的目录</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf, bool IsUploadImageServer, string uploadPath)
        {
            return this.Image(type, hpf, false, new ImageSize(), IsUploadImageServer, uploadPath);
        }
        /// <summary>
        /// 文件流上传
        /// 不生成缩略图集合，指定图像尺寸，可以选择上传到文件服务器
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="hpf">文件流</param>
        /// <param name="imageSize">尺寸</param>
        /// <param name="IsUploadImageServer">是上传到文件服务器</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf, ImageSize imageSize, bool IsUploadImageServer)
        {
            return this.Image(type, hpf, true, imageSize, IsUploadImageServer, null);
        }
        /// <summary>
        /// 文件流上传
        /// 不生成缩略图集合，指定图像尺寸，可以选择上传到文件服务器
        /// </summary>
        /// <param name="type"></param>
        /// <param name="hpf"></param>
        /// <param name="imageSize"></param>
        /// <param name="IsUploadImageServer"></param>
        /// <param name="uploadPath">指定上传的目录</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf, ImageSize imageSize, bool IsUploadImageServer, string uploadPath)
        {
            return this.Image(type, hpf, true, imageSize, IsUploadImageServer, uploadPath);
        }
        /// <summary>
        /// 文件流上传
        /// 可以指定是否生成缩略图集合，指定图像尺寸，可以选择上传到文件服务器
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="hpf">文件流</param>
        /// <param name="IsScale">是否生成缩略图</param>
        /// <param name="IsUploadImageServer">是上传到文件服务器</param>
        /// <returns></returns>
        public VMessage Image(UpLoadType type, HttpPostedFileBase hpf, bool IsScale, ImageSize imageSize, bool IsUploadImageServer, string uploadPath)
        {
            uploadPath = !string.IsNullOrWhiteSpace(uploadPath) ? uploadPath + "/" : uploadPath;
            HttpRequest Request = HttpContext.Current.Request;
            VMessage vmsg = new VMessage();

            if (this.IsImageVaild(type, hpf))
            {
                //本地相对路径
                string relativePath = string.Format(ConfigCache.ConfigFactory.Instance.GetConfig<FileLoadConfig>().LocationUploadPath + uploadPath, relativePathDic[type]);
                //服务器相对路径
                string serverRelativePath = string.Format(ConfigCache.ConfigFactory.Instance.GetConfig<FileLoadConfig>().ImageServerUploadPath + uploadPath, relativePathDic[type]);
                string path = HttpContext.Current.Server.MapPath(relativePath);
                DirectoryInfo di = new DirectoryInfo(path);
                if (!di.Exists)
                {
                    di.Create();
                }
                string guid = Guid.NewGuid().ToString();
                string fileName = string.Format("{0}{1}", guid, new FileInfo(hpf.FileName).Extension);//上传文件的名称
                string completeFileName = string.Format("{0}{1}", path, fileName);
                hpf.SaveAs(completeFileName);
                this.currPath = path;
                this.currFileName = fileName;


                //缩放
                if (IsScale)
                {
                    List<string> tmpName = new List<string>();
                    //生成指定尺寸的图像
                    if (imageSize.Width != 0 && imageSize.Height != 0)
                        tmpName.Add(CreateThumbnail(hpf, imageSize.Width, imageSize.Height, false));

                    switch (type)
                    {
                        case UpLoadType.UserFace:
                            foreach (ImageSize item in ImageSizeArr)
                            {
                                if (item.Width != 0 && item.Height != 0)
                                {
                                    tmpName.Add(CreateThumbnail(hpf, item.Width, item.Height));//生成缩放图片
                                }
                            }
                            break;

                        default:
                            break;
                    }

                    if (IsUploadImageServer)
                    {
                        if (tmpName.Count > 0)
                        {
                            foreach (var name in tmpName)
                            {
                                if (new FtpUpload().Upload(
                                    name,
                                    fileName,
                                    string.Format(serverRelativePath, relativePathDic[type])))
                                {
                                    new FileInfo(name).Delete();//删除本地文件
                                    vmsg.AddItem(string.Format(serverRelativePath, relativePathDic[type]) + fileName);

                                }
                            }
                        }
                    }

                }
                else
                {
                    if (IsUploadImageServer)
                    {

                        if (new FtpUpload().Upload(
                            completeFileName,
                            fileName,
                            string.Format(serverRelativePath, relativePathDic[type])))
                        {
                            new FileInfo(completeFileName).Delete();//删除本地文件
                            vmsg.AddItem(string.Format(serverRelativePath, relativePathDic[type]) + fileName);

                        }
                    }
                }

                if (IsUploadImageServer)
                    vmsg.AddItem(string.Format("{0}://{1}{2}{3}",
                                       Request.Url.Scheme,
                                       ConfigCache.ConfigFactory.Instance.GetConfig<FileLoadConfig>().ImageServerHost,
                                       string.Format(serverRelativePath, relativePathDic[type]).Replace('\\', '/'),
                                       fileName
                                   ));
                else
                    vmsg.AddItem(string.Format("{0}://{1}{2}{3}",
                                             Request.Url.Scheme,
                                             Request.Url.Authority,
                                             relativePath.Replace('\\', '/'),
                                             fileName
                                         ));
                vmsg.AddItem(guid);
            }
            else
            {
                vmsg.AddItemRange(this.GetRuleViolations(type, hpf));
            }
            return vmsg;
        }

        /// <summary>
        /// 上传到图像服务器
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public VMessage ImageToServer(string url)
        {
            VMessage vmsg = new VMessage();
            Uri uri = new Uri(url);
            string fileName = uri.Segments[uri.Segments.Length - 1];
            string typeStr = uri.Segments[uri.Segments.Length - 2];

            Utils.FileUpLoad(
                string.Format(
                ConfigCache.ConfigFactory.Instance.GetConfig<FileLoadConfig>().DefaultUploadUri,
                typeStr.TrimEnd('/')),
                HttpContext.Current.Server.MapPath(uri.LocalPath)
                );
            vmsg.AddItem(
               string.Format("{0}://{1}/upload/{2}{3}",
                   HttpContext.Current.Request.Url.Scheme,
                   ConfigCache.ConfigFactory.Instance.GetConfig<FileLoadConfig>().ImageServerHost,
                   typeStr,
                   fileName
               )
           );
            return vmsg;
        }
        #endregion

        #region 验证文件

        /// <summary>
        /// 文件是否有效
        /// </summary>
        /// <param name="type"></param>
        /// <param name="hpf"></param>
        /// <returns></returns>
        internal bool IsImageVaild(UpLoadType type, HttpPostedFileBase hpf)
        {
            return this.GetRuleViolations(type, hpf).Count() == 0;
        }

        /// <summary>
        /// 验证文件
        /// </summary>
        /// <param name="hpf"></param>
        /// <returns></returns>
        internal IEnumerable<string> GetRuleViolations(UpLoadType type, HttpPostedFileBase hpf)
        {
            if (!imgMIME.Contains(hpf.ContentType))// MIME
                yield return msgDIC[WarnEnum.ImgContentType];

            int contentLength = this.GetContentLengthByType(type);//文件大小
            if (hpf.ContentLength > contentLength)
                yield return string.Format(msgDIC[WarnEnum.ImgContentLength], contentLength / 1024);

            if (!imgExtension.Contains(hpf.FileName.Substring(hpf.FileName.LastIndexOf('.') + 1).ToLower()))//文件后缀
                yield return msgDIC[WarnEnum.ImgExtension];

            yield break;

        }
        #endregion

        #region 根据 FileUpLoadContentLengthType 类型 获取相应的大小
        /// <summary>
        /// 根据 FileUpLoadContentLengthType 类型 获取相应的大小
        /// </summary>
        /// <param name="type">文件上传大小枚举值</param>
        /// <returns>返回</returns>
        int GetContentLengthByType(UpLoadType type)
        {
            switch (type)
            {

                case UpLoadType.FileUrl:
                    return 0xA00000;
                case UpLoadType.Image:
                    return 0xA00000;
                case UpLoadType.UserFace:
                    return 0xA00000;//10M
                default:
                    throw new Exception("可能有错误");
            }
        }
        #endregion

        #region 图像缩放

        public string CreateThumbnail(HttpPostedFileBase file, double width, double height)
        {
            return CreateThumbnail(file, width, height, true);
        }
        /// <summary>
        /// 建立压缩图片
        /// </summary>
        /// <param name="file"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="isEqualScale">是否等比例缩放</param>
        public string CreateThumbnail(HttpPostedFileBase file, double width, double height, bool isEqualScale)
        {
            Bitmap bit;
            Rectangle r;
            Point point = new Point(0, 0); //图像从那个坐标点进行截取
            int newWidth = 0, newHeight = 0;
            double wRate = 1, hRate = 1, setRate = 1;
            System.Drawing.Image image = System.Drawing.Image.FromStream(file.InputStream);
            bit = new Bitmap((int)(width), (int)(height));
            if (isEqualScale)
            {
                if (image.Height > height)
                {
                    hRate = (double)height / image.Height;
                }

                if (image.Width > width)
                {
                    wRate = (double)width / image.Width;
                }

                if (wRate != 1 || hRate != 1)
                {
                    if (wRate > hRate)
                    {
                        setRate = hRate;
                    }
                    else
                    {
                        setRate = wRate;
                    }
                }

                newWidth = (int)(image.Width * setRate);
                newHeight = (int)(image.Height * setRate);
                if (height > newHeight)
                {
                    point.Y = Convert.ToInt32(height / 2 - newHeight / 2);
                }
                if (width > newWidth)
                {
                    point.X = Convert.ToInt32(width / 2 - newWidth / 2);
                }
                r = new Rectangle(point.X, point.Y, newWidth, newHeight);
            }
            else
            {
                r = new Rectangle(0, 0, (int)(width), (int)(height));
            }
            Graphics g = Graphics.FromImage(bit);
            g.Clear(Color.White);
            g.DrawImage(image, r);
            MemoryStream ms = new MemoryStream();
            bit.Save(ms, ImageFormat.Jpeg);
            byte[] bytes = ms.ToArray();
            string fileName = GetOutputFile(this.currPath, this.currFileName, (int)width, (int)height);
            using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                stream.Write(bytes, 0, bytes.Length);
            }
            bit.Dispose();
            ms.Dispose();
            image.Dispose();
            return fileName;
        }
        #endregion

        #region 输出地址
        public static string GetOutputFile(string currPath, string currFileName)
        {
            return Path.Combine(currPath, currFileName);
        }

        public static string GetOutputFile(string currPath, string currFileName, int width, int height)
        {
            return Path.Combine(currPath //固定为JPG
                , string.Format("{0}_{1}×{2}.jpg", currFileName, width, height));
        }
        #endregion

    }

    /// <summary>
    /// 图像尺寸结构
    /// </summary>
    public struct ImageSize
    {
        public int Width { get; set; }
        public int Height { get; set; }

        public ImageSize(int width, int height)
            : this()
        {
            this.Width = width;
            this.Height = height;
        }
    }
}
